package com.radiusmess;

import java.io.*;
import java.util.*;


public class RadiusTester {
	private  byte[] auth_content;
	private  byte[] acct_content;
	private  byte[] acct_cont;
    private ByteArrayOutputStream bStream = null;
	private RadiusInformation ri = new RadiusInformation();
	
	private int auth_identifier = 1;
    private int acct_identifier = 1;

	private Date timestamp = new Date();
	private Random radomnumber = new Random(timestamp.getTime());
	private byte[] auth_authenticat = new byte[16];
    private byte[] acct_authenticat = new byte[16];
		
    
    public RadiusTester(RadiusInformation ri) {
      this.ri.copyfrom(ri);
    }
    public RadiusTester(){
    }
	public byte[] getAuthContent( ) {
		return auth_content;
	}

    public byte[] getAcctContent() {
    	return acct_content;
   }
        
    /**
     * 16进制
     * @param ib
     * @return
     */
	public static String byteHEX(byte[] ib) {
		String s = new String("");
		char[] Digit = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
		char [] ob = new char[2];

		for (int i = 0; i < ib.length; i++) {
			ob[0] = Digit[(ib[i] >>> 4) & 0X0F];
			ob[1] = Digit[ib[i] & 0X0F];
			s +=  new String(ob);
		}
		return s;
	}
	
	/**
	 * 
	 * 生成报文
	 */
	public void makePackage(boolean isAuth,boolean onLine) throws Exception {
		
		String verifyMess =null; 
		
		
		if (ri.getUserName() == null || ri.getUserName().equals(""))
			throw new Exception("用户名为空");
		if (ri.getRadiusKey() == null || ri.getRadiusKey().equals(""))
			throw new Exception("key为空");

			//Prepare byte tream
                if (bStream == null)
                  bStream = new ByteArrayOutputStream(1024);
                else
                  bStream.reset();
                //报文头部
                makePackageHead(isAuth);
                	
                if (isAuth) {
                  for (int i = 0; i < 16; i++) {
                    auth_authenticat[i] = (byte)(radomnumber.nextInt() & 0x00FF);
                  }
                  makePackageStrAttr(1, ri.getUserName());
                  makePasswordAttr();
                
                  bStream.flush();
                  
                  auth_content = new byte[bStream.toByteArray().length];
                  for (int i = 0; i < bStream.toByteArray().length; i++) {
                    auth_content[i] = (bStream.toByteArray())[i];
                  }

                  int packagelen = auth_content.length;
                  auth_content[2] = (byte)((packagelen & 0x0000FF00) >>> 8);
                  auth_content[3] = (byte)(packagelen & 0x000000FF);

                  for (int i = 0; i < 16; i++){
                      auth_content[4 + i] = auth_authenticat[i];
                   }
                  
                  
                  System.out.println("auth_content---------------"+ byteHEX(auth_content));
             
                  
                } else {
                	makePackageStrAttr(1, ri.getUserName());
                	if(onLine){
                		makePackageIntAttr(40, 1); //Acct-Status-Type
                	}else{
                		makePackageIntAttr(40, 2); //Acct-Status-Type
                	}
                	
                	
                  makePackageStrAttr(44, "" +ri.getSessId());
            

                  bStream.flush();
                  acct_content = new byte[bStream.toByteArray().length];
                  for (int i = 0; i < bStream.toByteArray().length; i++) {
                    acct_content[i] = (bStream.toByteArray())[i];
                  }

                  int packagelen = acct_content.length;
                  acct_content[2] = (byte)((packagelen & 0x0000FF00) >>> 8);
                  acct_content[3] = (byte)(packagelen & 0x000000FF);
                  
                  
                  acct_cont = new byte[bStream.toByteArray().length];
                  for (int i = 0; i < bStream.toByteArray().length; i++) {
                    acct_cont[i] = (bStream.toByteArray())[i];
                  }

                  int pa = acct_cont.length;
                  acct_cont[2] = (byte)((pa & 0x0000FF00) >>> 8);
                  acct_cont[3] = (byte)(pa & 0x000000FF);
                  byte[] b= new byte[16];
                  for (int i = 0; i < 16; i++) {
                      acct_content[4 +  i] = b[i];
                    }
                  

                  makeAcctAuthenticate();

                  for (int i = 0; i < 16; i++) {
                    acct_content[4 +  i] = acct_authenticat[i];
                  }
                  
           
                 }
               
                
	}
	/**
	 * 
	 *报文头部生成
	 * @param isAuth
	 * @throws Exception
	 */
	private void makePackageHead(boolean isAuth) throws Exception {
          //Process package header
          if (isAuth) {
        	bStream.write(1);
        	auth_identifier = Ident.getIdemt();
            bStream.write(auth_identifier);
          } else {
            bStream.write(4);
            acct_identifier = auth_identifier = Ident.getIdemt();;
            bStream.write(acct_identifier);
          }

          for (int i = 0; i < 18; i++)
            bStream.write(0);
		}
	
	/**
	 * 
	 * 报文attributes属性  1
	 * @param attrNo
	 * @param attr  String 
	 * @throws Exception
	 */
	
	private void makePackageStrAttr( int attrNo, String attr ) throws Exception {
		if (attrNo < 1 || attrNo > 255)
			return;
		if (attr == null || attr.equals(""))
			return;

		try {
			bStream.write(attrNo);
			bStream.write(attr.length() + 2);
			bStream.write(attr.getBytes());
		} catch (Exception e) {
			throw new Exception("RadiusTester::makePackageStrAttr: 内存分配错误" + "\n" + e);
		}
	}
	/**
	 * 
	 * 报文attributes属性  2
	 * @param attrNo
	 * @param attr  int
	 * @throws Exception
	 */
	private void makePackageIntAttr( int attrNo, long attr ) throws Exception {
		if (attrNo < 1 || attrNo > 255)
			return;
		if (attr == -1)
			return;

		try {
			bStream.write(attrNo);
			bStream.write(6);
			bStream.write((int)((attr & 0xFF000000) >>> 24));
			bStream.write((int)((attr & 0x00FF0000) >>> 16));
			bStream.write((int)((attr & 0x0000FF00) >>> 8 ));
			bStream.write((int)(attr & 0x000000FF));
		}catch (Exception e) {
			throw new Exception("RadiusTester::makePackageIntAttr: 内存分配错误" + "\n" + e);
		}
	}
	/**
	 * 
	 * 密码处理
	 * @throws Exception
	 */
	private void makePasswordAttr( ) throws Exception {
		if (ri.getPassword() == null || ri.getPassword().equals(""))
			return;

		byte[] enpassword = new byte[16];
		byte[] depassword = ri.getPassword().getBytes();
		ByteArrayOutputStream bs;

		try {
			bs = new ByteArrayOutputStream(256);
			bs.write(ri.getRadiusKey().getBytes()); 
			bs.write(auth_authenticat);
		} catch (Exception e) {
			throw new Exception("RadiusTester::makePasswordAttr: 内存分配错误" + "\n" + e);
		}

		MD5 md5 = new MD5();
		md5.MD5_calc(enpassword, bs.toByteArray(), bs.size());

		for (int i = 0; i < enpassword.length && i < depassword.length; i++)
			enpassword[i] = (byte)(enpassword[i]^depassword[i]);

		try {
			bStream.write(2);
			bStream.write(enpassword.length + 2);
			bStream.write(enpassword);
		} catch (Exception e) {
			throw new Exception("RadiusTester::makePasswordAttr: 内存分配错误" + "\n" + e);
		}
	}
	/*//NasIp处理
	private void makeNasIpAttr() throws Exception{
		if (ri.getNasIp() == null || ri.getNasIp().equals(""))
			return;
		try {
			bStream.write(4);
			bStream.write(6);
			String[] ips = ri.getNasIp().split("[.]");
			for (int i = 0; i < 4; i++) {
				int m = Integer.parseInt(ips[i]);
				bStream.write(m);
			}
		}catch (Exception e) {
			throw new Exception("RadiusTester::makePackageIntAttr:  内存分配错误" + "\n" + e);
		}
	}*/
	
		/**
		 * 验证字
		 * @throws Exception
		 */
        private void makeAcctAuthenticate() throws Exception{
          ByteArrayOutputStream bs;
          try {
            bs = new ByteArrayOutputStream(1024);
            bs.write(acct_cont);
            bs.write(ri.getRadiusKey().getBytes());
          } catch (Exception e) {
              throw new Exception("RadiusTester::makeAcctAuthenticate: 分配内存错误" + "\n" + e);
          }

          MD5 md5 = new MD5();
          md5.MD5_calc(acct_authenticat, bs.toByteArray(), bs.size());
        }

        public int verifyPackage(byte[] buffer) {
          if ((int)buffer[0] == 2 ) {
            return 1;
          } else if ((int)buffer[0] == 3) {
            return 2;
          } else {
            return 0;
          }
        }
		
		public byte[] getAcct_authenticat() {
			return acct_authenticat;
		}
		public void setAcct_authenticat(byte[] acct_authenticat) {
			this.acct_authenticat = acct_authenticat;
		}
		public byte[] getAuth_authenticat() {
			return auth_authenticat;
		}
		public void setAuth_authenticat(byte[] auth_authenticat) {
			this.auth_authenticat = auth_authenticat;
		}

    
	
	
}

